package GUI;

import game.ItemContainer;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Paint;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Vector;

import javax.swing.JPanel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class ThumbList extends JPanel implements ComponentListener, MouseListener, MouseWheelListener, ActionListener
{
	private static final long serialVersionUID = -4287594935988943939L;

	private class ListItem
	{
		public Object item = null;
		public boolean selected = false;
	}
	
	private ItemContainer cont = null;
	private boolean allowTooltips = true;
	
	private int itemHeight = 50;
	private int itemCount = 0;
	
	private int sbWidth = 5;
	private int off = 0;
	
	private Vector<ListItem> list = new Vector<ListItem>();
	private ArrayList<ListSelectionListener> listeners = new ArrayList<ListSelectionListener>();
	private ThumbListAdapter adapter = null;
	private boolean allowMultiSelection = false;
	private Window tooltipParentWindow = null;
	
	public Window getTooltipParentWindow() {
		return tooltipParentWindow;
	}

	public void setTooltipParentWindow(Window tooltipParentWindow) {
		this.tooltipParentWindow = tooltipParentWindow;
	}

	private Paint grad = new LinearGradientPaint(0.0f, 0.0f, 0.0f, 50.0f,
			new float[] { 0.0f, 1.0f }, new Color[] { new Color(0, 0, 255), new Color(0, 0, 64) },
			java.awt.MultipleGradientPaint.CycleMethod.REPEAT);
	
	public ThumbList(ThumbListAdapter dataAdapter)
	{
		this.adapter = dataAdapter;
		this.setBackground(new Color(64, 64, 64));
		this.addMouseListener(this);
		this.addMouseWheelListener(this);
		
		if(cont != null)
		{
			cont.addActionListener(this);
		}
	}
	
	public void refreshList()
	{
		if(off > list.size() - itemCount) off = list.size() - itemCount;
		if(off < 0) off = 0;
		repaint();
	}
	
	public void paint(Graphics gg)
	{
		Graphics2D g = (Graphics2D)gg;
		g.setColor(this.getBackground());
		g.fillRect(0, 0, this.getWidth(), this.getHeight());
		paintList(g);
	}
	
	public void paintList(Graphics2D g)
	{
		int remH = this.getHeight();
		
		itemCount = remH / itemHeight; 
		
		for(int i = 0, n = off; i < itemCount; ++i, ++n)
		{
			if(n >= 0 && n < list.size())
			{
				if(list.get(n).selected)
				{
					g.setPaint(grad);
					g.fillRect(0, i * itemHeight, this.getWidth(), itemHeight);
				}
				
				if(adapter != null)
				{
					BufferedImage image = adapter.getThumbnail(list.get(n).item);
					if(image != null)
					{
						g.drawImage(image, 5, i * itemHeight, itemHeight, itemHeight, null);
						
						ButtonSkin.drawText(g, adapter.getText(list.get(n).item),
								Color.white, 30, i * itemHeight,
								this.getWidth(), itemHeight, ButtonSkin.LEFT, false);
					}
					else
					{
						ButtonSkin.drawText(g, adapter.getText(list.get(n).item),
								Color.white, 5, i * itemHeight,
								this.getWidth(), itemHeight, ButtonSkin.LEFT, false);
					}
					
				}
				else
				{
					System.out.println("NO ADAPTER");
					ButtonSkin.drawText(g, list.get(n).item.toString(),
							Color.white, 5, i * itemHeight,
							this.getWidth(), itemHeight, ButtonSkin.LEFT, false);
				}
			}
		}
		
		if(list.size() > itemCount)
		{
			g.setColor(Color.blue);
			float factor = (float)itemCount / list.size();
			int sbSize = (int) (factor * (float)remH);
			int bar = remH - sbSize;
			int oY = (int) (((float)off / (float)(list.size() - itemCount)) * (float)bar);
			g.fillRect(this.getWidth() - sbWidth - 3, oY, sbWidth, sbSize);
		}
	}

	@Override
	public void componentResized(ComponentEvent arg0)
	{
		//filterWidth = this.getWidth() / 5;
	}
	
	@Override
	public void componentHidden(ComponentEvent arg0){}
	@Override
	public void componentMoved(ComponentEvent arg0){}
	@Override
	public void componentShown(ComponentEvent arg0){}
	@Override
	public void mouseClicked(MouseEvent e){}
	@Override
	public void mouseEntered(MouseEvent e){}
	@Override
	public void mouseExited(MouseEvent e){}
	@Override
	public void mousePressed(MouseEvent e){}

	public Vector<Object> getSelectedItems()
	{
		Vector<Object> sel = new Vector<Object>();
		for(ListItem ci : list)
			if(ci.selected)
				sel.add(ci.item);
		return sel;
	}
	
	@Override
	public void mouseReleased(MouseEvent e)
	{
		
		int n = e.getY() / itemHeight;
		if(n < 0 || n >= itemCount) return;
		
		int i = n + off;
		if(i >= 0 && i < list.size())
		{
			if(e.isShiftDown() && allowMultiSelection)
			{
				list.get(i).selected = !list.get(i).selected;
				notifyListeners();
			}
			else
			{
				for(int x = 0; x < list.size(); ++x)
					list.get(x).selected = x == i;
				notifyListeners();
				
				if(e.getButton() == MouseEvent.BUTTON3 && allowTooltips && adapter != null)
				{
					if(tooltipParentWindow == null)
					{
						if(this.getTopLevelAncestor() instanceof Window)
							tooltipParentWindow = (Window) this.getTopLevelAncestor();
					}
					if(tooltipParentWindow != null)
						InfoWindow.showToolTip(adapter.getTooltip(list.get(i).item),
								e.getXOnScreen(), e.getYOnScreen(), tooltipParentWindow);
				}
			}
			
			repaint();
		}
	}

	@Override
	public void mouseWheelMoved(MouseWheelEvent arg0) {
		off += arg0.getWheelRotation();
		
		if(off > list.size() - itemCount) off = list.size() - itemCount;
		if(off < 0) off = 0;
		
		repaint();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		refreshList();
		repaint();
	}
	
	public ItemContainer getItemContainer()
	{
		return cont;
	}
	
	public void clear()
	{
		list.clear();
		refreshList();
		repaint();
	}
	
	public void addElement(Object item)
	{
		ListItem i = new ListItem();
		i.item = item;
		i.selected = false;
		list.add(i);
		repaint();
	}
	
	public void removeElement(Object item)
	{
		for(int i = 0; i < list.size(); ++i)
		{
			if(list.get(i).item == item)
			{
				list.remove(i);
				i--;
			}
		}
		repaint();
	}
	
	public void addAllElements(Collection<?> collection)
	{
		for(Object o : collection)
		{
			ListItem i = new ListItem();
			i.item = o;
			i.selected = false;
			list.add(i);
		}
		repaint();
	}
	
	public void selectAll()
	{
		for(ListItem ci : list)
			ci.selected = true;
		repaint();
		notifyListeners();
	}
	
	public void selectNone()
	{
		for(ListItem ci : list)
			ci.selected = false;
		repaint();
		notifyListeners();
	}
	
	public void selectItems(Vector<Object> items)
	{
		for(ListItem ci : list)
			ci.selected = items.contains(ci.item);
		repaint();
		notifyListeners();
	}
	
	public void setSelectedIndex(int index)
	{
		for(int i = 0; i < list.size(); ++i)
			list.get(i).selected = i == index;
		repaint();
		notifyListeners();
	}
	
	public void addListSelectionListener(ListSelectionListener listener)
	{
		listeners.add(listener);
	}
	
	public void removeListSelectionListener(ListSelectionListener listener)
	{
		listeners.remove(listener);
	}
	
	private void notifyListeners()
	{
		int minI = -1, maxI = -1, i = 0;
		for(ListItem li : list)
		{
			if(li.selected)
			{
				if(minI == -1)
					minI = i;
				
				if(i > maxI)
					maxI = i;
			}
			i++;
		}
		ListSelectionEvent lse = new ListSelectionEvent(this, minI, maxI, false);
		
		for(i = 0; i < listeners.size(); ++i)
			listeners.get(i).valueChanged(lse);
	}
	
	public int getSelectedIndex()
	{
		int i = 0;
	
		for(ListItem li : list)
		{
			if(li.selected)
			{
				return i;
			}
			i++;
		}
		
		return -1;
	}

	public boolean doesAllowTooltips() {
		return allowTooltips;
	}

	public void setAllowTooltips(boolean allowTooltips) {
		this.allowTooltips = allowTooltips;
	}

	public int getItemHeight() {
		return itemHeight;
	}

	public void setItemHeight(int itemHeight) {
		this.itemHeight = itemHeight;
		grad = new LinearGradientPaint(0.0f, 0.0f, 0.0f, itemHeight,
				new float[] { 0.0f, 1.0f }, new Color[] { new Color(0, 0, 255), new Color(0, 0, 64) },
				java.awt.MultipleGradientPaint.CycleMethod.REPEAT);
		repaint();
	}

	public ThumbListAdapter getAdapter() {
		return adapter;
	}

	public void setAdapter(ThumbListAdapter adapter) {
		this.adapter = adapter;
		repaint();
	}

	public boolean isAllowMultiSelection() {
		return allowMultiSelection;
	}

	public void setAllowMultiSelection(boolean allowMultiSelection) {
		this.allowMultiSelection = allowMultiSelection;
		boolean sel = false;
		for(ListItem li : list)
			if(li.selected)
				if(sel)
					li.selected = false;
				else
					sel = li.selected = true;
	}
}
